﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Messaging;
using System.Windows.Interop;

namespace Songhay.Silverlight.BiggestBox
{
    using Composition;
    using Extensions;
    using Songhay.Mvvm.Extensions;
    using Songhay.Mvvm.Models;
    using Songhay.Mvvm.ViewModels;
    using Songhay.Mvvm.Views;
    using Views;

    /// <summary>
    /// Defines the MEF Composition Host for this application.
    /// </summary>
    public sealed class BiggestBoxCompositionHost : CompositionHost, INavigationCompositionHost
    {
        #region INavigationCompositionHost members:

        /// <summary>
        /// The pages, hosted by the MEF Composition.
        /// </summary>
        /// <remarks>
        /// This is a public Property for Silverlight security reasons
        /// (for <c>Microsoft.Internal.ReflectionInvoke.SafeInvoke</c> in MEF).
        /// The WPF equivalent can be a private field.
        /// </remarks>
        [ImportMany(typeof(Page))]
        public IEnumerable<Page> ComposedPages { get; set; }

        /// <summary>
        /// Gets the page, hosted by the MEF Composition.
        /// </summary>
        /// <param name="typeName">
        /// Name of the type
        /// of the <see cref="System.Windows.Controls.Page"/>.
        /// </param>
        public Page GetPage(string typeName)
        {
            if(this.ComposedPages == null)
                throw new Exception("The Composed Pages are null.");

            var page = this.ComposedPages
                .FirstOrDefault(p =>
                    !string.IsNullOrEmpty(typeName) &&
                    p.GetType().Name.Contains(typeName));

            if(page == null)
            {
                page = new ApplicationMessagePage();
                this.NavigationTarget.SetNavigationContent(page);

                var data = new ApplicationMessagePageViewModel
                {
                    ApplicationMessage = "Page, " + (typeName ?? "[unknown]") + ", not found.",
                    IsErrorMessage = true,
                    PageTitle = "Page not found.",
                };

                var message = new LightNavigationMessage<ApplicationMessagePageViewModel>(data);
                Messenger.Default.Send(message);
            }

            return page;
        }

        /// <summary>
        /// Gets the root visual
        /// of this application.
        /// </summary>
        /// <remarks>
        /// The conventional Application Loader uses Reflection to call this method.
        /// This call usually instantiates the Host singleton.
        /// </remarks>
        public UserControl GetRootVisual()
        {
            var visual = new ClientView();
            return visual;
        }

        /// <summary>
        /// Sets the Silverlight host.
        /// </summary>
        /// <param name="host">The host.</param>
        public void SetSilverlightHost(SilverlightHost host)
        {
            this.NavigationHost = host;
        }

        #endregion

        /// <summary>
        /// Gets the MEF Host.
        /// </summary>
        /// <value>The MEF Host.</value>
        public static BiggestBoxCompositionHost MefHost
        {
            get { return compositionHost; }
        }

        /// <summary>
        /// Gets or sets the navigation target.
        /// </summary>
        /// <value>The navigation target.</value>
        internal Frame NavigationTarget { get; set; }

        /// <summary>
        /// Gets or sets the navigation host.
        /// </summary>
        /// <value>The navigation host.</value>
        internal SilverlightHost NavigationHost { get; private set; }

        /// <summary>
        /// Initializes a new instance
        /// of the <see cref="BiggestBoxCompositionHost"/> class.
        /// </summary>
        BiggestBoxCompositionHost()
        {
            byte numberOfOperations = 3;
            var catalogs = new DeploymentCatalog[numberOfOperations];
            var operations = new AsyncOperationGroup(numberOfOperations,
            () =>
            {
                catalogs.ForEachInEnumerable(i => this.AddToAggregateCatalog(i));
                base.Compose();

                if(this.CompositionMessaging != null)
                    this.CompositionMessaging.ForEachInEnumerable(
                    i =>
                    {
                        i.RegisterMessageReceivers();
                        i.SendCompositionMessages();
                    });

                var message = new LightMessage<string>("BiggestBoxCompositionHost")
                {
                    Source = LightMessageSource.ApplicationComposed
                };
                Messenger.Default.Send(message);
            });

            Uri uri;

            //Catalog the XAP downloaded by the Application Loader, the BiggestBox Index:
            uri = new Uri(Application.Current.
                Host.InitParams["LoaderInfoXapPath"], UriKind.Relative);
            catalogs[0] = CompositionUtility.DownloadCatalog(uri,
            (s, args) =>
            {
                operations.MarkOperationComplete(0);
            });

            //Catalog the XAP with the BiggestBox Index Part:
            uri = new Uri(Application.Current
                .Host.InitParams["BiggestBoxIndexXapPath"], UriKind.Relative);
            catalogs[1] = CompositionUtility.DownloadCatalog(uri,
            (s, args) =>
            {
                operations.MarkOperationComplete(1);
            });

            //Catalog the XAP with the Additional Samples Part:
            uri = new Uri(Application.Current
                .Host.InitParams["BiggestBoxAdditionalSamplesXapPath"], UriKind.Relative);
            catalogs[2] = CompositionUtility.DownloadCatalog(uri,
            (s, args) =>
            {
                operations.MarkOperationComplete(2);
            });
        }

        /// <summary>
        /// The singleton read-only instance.
        /// </summary>
        static readonly BiggestBoxCompositionHost compositionHost = new BiggestBoxCompositionHost();

    }
}
